import { getUuid } from "../common/index.js";
import { isElement } from "lodash";
import { ElMessage, MessageHandler } from "element-plus";
import { h } from "vue";
/**
 * 将html img元素转换为base64
 * @param img 图片的HTML元素
 * @returns 该图片的base64内容
 */
export function getImgBase64(img: HTMLImageElement): {
  data: string;
  ext: string;
  base64: string;
} {
  // 创建一个空的canvas元素
  const canvas = document.createElement("canvas");
  canvas.width = img.width;
  canvas.height = img.height;
  // @ts-ignore Copy the image contents to the canvas
  const ctx: CanvasRenderingContext2D = canvas.getContext("2d");
  ctx.drawImage(img, 0, 0);
  // Get the data-URL formatted image
  // Firefox supports PNG and JPEG. You could check img.src to
  // guess the original format, but be aware the using "image/jpg"
  // will re-encode the image.
  const dataURL = canvas.toDataURL("image/png");
  const reg = /^data:image\/(?<ext>\w+);base64,/;
  const {
    //@ts-ignore
    groups: { ext },
  } = reg.exec(dataURL);
  return { data: dataURL.replace(reg, ""), ext, base64: dataURL };
}

/**
 * 页面上是否存在css选择器指定的元素
 * @param css css选择器
 * @returns 是否存在该元素
 */
export function exists(css: string): boolean {
  let $ = require("jquery");
  return $(css).length > 0;
}

/**
 * 在页面底部显示url
 */
export function showUrl(): void {
  let $ = require("jquery");
  $(document.body).prepend(
    `<div style="position:fixed;width: calc(100vw - 20px);bottom:0px;z-index:9999;background-color:#fff;">
        <div class="example-showcase">
          <div class="el-input el-input--default el-input-group el-input-group--append">
            <input
              id="my-preload-common-href"
              class="el-input__inner"
              type="text"
              autocomplete="off"
              placeholder="Please input"
            />
            <div id="my-preload-common-href-go" class="el-input-group__append" style="cursor:pointer;">转到</div>
          </div>
        </div>
      </div>`
  );
  let history = "";
  setInterval(() => {
    history !== window.location.href &&
      $("#my-preload-common-href").val(window.location.href);
    history = window.location.href;
  }, 500);
  const cb = () => {
    // @ts-ignore
    let inputVal: string = $("#my-preload-common-href").val();
    /https?:\/{2}/i.test(inputVal) || (inputVal = "http://" + inputVal);
    window.location.href = inputVal;
  };
  $("#my-preload-common-href-go").on("click", cb);
  // @ts-ignore
  $("#my-preload-common-href").each((i: number, n: HTMLElement) => {
    n.addEventListener("keydown", ({ key }) => /enter/i.test(key) && cb());
  });
}

export interface StartCountDownOptions {
  /**
   * 倒计时内的span的id
   */
  spanId?: string;
  /**
   * 倒计时的总毫秒数
   */
  duration?: number;
  /**
   * 倒计时所使用的减小间隔
   */
  interval?: number;
  /**
   * 用于显示timeleft的函数，返回字符串
   */
  countDownMessage?: (
    /**
     * 剩余的毫秒数
     */
    timeLeft: number
  ) => string;
  /**
   * 是否显示"取消"
   */
  showCancel?: boolean;
  /**
   * 是否显示"立即"
   */
  showStart?: boolean;
  /**
   * 是否显示"重新"
   */
  showRestart?: boolean;
  /**
   * 是否显示"重新"
   */
  beforeStart?: Function;
  /**
   * 倒计时取消时运行的函数
   */
  fail?: Function;
  /**
   * 倒计时结束时运行的函数
   */
  success?: Function;
  /**
   * 每间隔都运行的函数
   */
  every?: Function;
}
/**
 * 创建一个倒计时窗口
 * @param option 倒计时参数
 * @returns 倒计时窗口的实例
 */
export function startCountDown({
  spanId = getUuid(),
  duration = 10 * 1000,
  interval = 100,
  countDownMessage = (timeLeft: number) => `剩余${timeLeft}毫秒`,
  showCancel = true,
  showStart = true,
  showRestart = false,
  beforeStart = () => 0,
  fail = () => 0,
  success = () => 0,
  every = () => 0,
}: StartCountDownOptions): {
  msg: MessageHandler;
  promise: Promise<1>;
} {
  let $ = require("jquery");
  beforeStart();
  const innerMsg = [];
  const styleConfig = {
    class: "el-button el-button--text",
    style: "display:inline;",
  };
  showRestart &&
    innerMsg.push(
      h("span", { id: `${spanId}Restart`, ...styleConfig }, "重新")
    );
  showStart &&
    innerMsg.push(h("span", { id: `${spanId}Start`, ...styleConfig }, "立即"));
  showCancel &&
    innerMsg.push(h("span", { id: `${spanId}Cancel`, ...styleConfig }, "取消"));
  const message = h("div", { style: "line-height:1.5;" }, [
    h(
      "span",
      { id: `${spanId}`, style: "margin-right:15px;" },
      countDownMessage(duration)
    ),
    ...innerMsg,
  ]);
  const msg = ElMessage({ duration: duration + 10, message });
  return {
    msg,
    promise: new Promise((resolve, reject) => {
      let _timeLeft = duration;
      let _timer: number | undefined;
      /**
       *
       */
      function _successCallback() {
        clearInterval(_timer);
        $(`#${spanId}`).text(countDownMessage(0));
        $(`#${spanId}Cancel`).remove();
        $(`#${spanId}Start`).remove();
        msg.close();
        success();
        resolve(1);
      }
      /**
       *
       */
      function _failCallback() {
        clearInterval(_timer);
        $(`#${spanId}Cancel`).remove();
        $(`#${spanId}Start`).remove();
        msg.close();
        fail(); // 如果点击了取消就运行fail这个function
        // eslint-disable-next-line prefer-promise-reject-errors
        reject("Countdown Cancelled"); // 并且返回catch
      }
      $(`#${spanId}Restart`).click(() => {
        _timeLeft = duration;
        $(`#${spanId}`).text(countDownMessage(_timeLeft));
      });
      $(`#${spanId}Start`).click(_successCallback);
      $(`#${spanId}Cancel`).click(_failCallback);
      // @ts-ignore
      _timer = setInterval(() => {
        every(_timeLeft);
        if (_timeLeft < interval) {
          _successCallback();
        } else {
          _timeLeft -= interval;
          $(`#${spanId}`).text(countDownMessage(_timeLeft));
        }
      }, interval);
    }),
  };
}

/**
 * 字面量是否为html元素
 */
export const isHTMLElement = isElement;

/**
 * 根据window.location获取ws://或者wss://开头的url
 * @param route 后面的路径
 * @returns 类似于wss://localhost:8080的地址
 */
export function getWsAddress(route: `/${string}` | "" = ""): string {
  const { protocol, host } = location;
  const wsProtocol = protocol.replace("http", "ws");
  return `${wsProtocol}//${host}${route}`;
}

/**
 * 批量处理ws.onmessage事件
 * @param handlers 收到msg之后的函数, 其中msg已经JSON.parse过了
 * @param ws WebSocket实例
 */
export function wsOn(
  handlers: ((
    /**
     * 已尝试过JSON.parse的data
     */
    data: any
  ) => any | void)[] = [],
  ws: WebSocket = new WebSocket(getWsAddress())
): WebSocket {
  ws.onmessage = ({ data }) => {
    for (const func of handlers) {
      try {
        func(JSON.parse(data));
      } catch (error) {
        func(data);
      }
    }
  };
  return ws;
}

/**
 * 利用ws发送JSON数据
 * @param msg 要用ws发送的数据
 * @param ws WebSocket实例
 */
export function wsSend(msg: any, ws: WebSocket): void {
  ws.send(JSON.stringify(msg));
}

/**
 * 通过点击打开<a>标签打开链接
 * @param href 链接地址
 * @param target 打开方式
 */
export function clickOpenLink(
  href: string = "/",
  target: "_blank" | "_self" | "_parent" | "_top" | string = "_blank"
): void {
  let $ = require("jquery");
  const id = "a" + getUuid();
  $(document.body).append(
    `<a id ="${id}" href="${href}" target="${target}"></a>`
  );
  // @ts-ignore
  $("#" + id).each((i: number, n: HTMLAnchorElement) => n.click());
  $("#" + id).remove();
}

/**
 * @deprecated
 * 是否在已启用了electron Remote的electron-browser-window里
 * 已弃用，可以直接复制本段源码使用
 * @returns 是否在已启用了electron Remote的electron-browser-window里
 */
export function isInElectronBrowser(): boolean {
  try {
    require("@electron/remote").getCurrentWindow();
    return true;
  } catch (error) {
    return false;
  }
}

/**
 * 等待DOMContentLoaded事件
 * @param cb 在DOMContentLoaded之后运行的函数
 * @returns 在DOMContentLoaded之后返回Promise<true>
 */
export function onPreload(cb: () => any | void): Promise<true> {
  return new Promise((resolve) => {
    let loadOk = 0;
    if (window.frames.length === parent.frames.length) {
      // 只在主页面而不是iframe中运行
      window.addEventListener("DOMContentLoaded", () => {
        console.log("-----------   DOMContentLoaded   ---------");
        loadOk || resolve(true);
        loadOk || cb();
        loadOk++;
      });
    }
  });
}
